package org.yxing.palpalgps.http;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpException;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import org.yxing.palpalgps.R;
import org.yxing.palpalgps.oauth.OAuth;
import org.yxing.palpalgps.utils.ErrorMessage;
import org.yxing.palpalgps.utils.Utils;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

public class AsyncRequest {
    private static final String TAG = "AsyncRequest";
    private static final int NET_ERROR = 0;
    private static final int FETCH_DATA_FINISH = 1;
    private Context mContext;
    private ProgressDialog mProgressDialog;
    private boolean isShowProgressDialog = true;
    
    private FetchListener mFetchListener;
    
    public AsyncRequest(Context context) {
        mContext = context;
        mProgressDialog = new ProgressDialog(mContext);
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        mProgressDialog.setMessage(mContext.getString(R.string.progress));
    }
    
    /**
     * @deprecated
     * @param url
     * @param params
     * @param listener
     */
    public void request(final String url, final List<BasicNameValuePair> params, final RequestJsonListener listener) {
        mProgressDialog.show();
        Runnable runnable = new Runnable(){
            public void run() {
                try {
                    String response = requestData(url, params, listener);
                    if (response != null) {
                        JSONObject json = new JSONObject(response);
                        int errorCode;
                        if ((errorCode = json.getInt("error_code")) == 0) {
                            listener.onComplete(json);
                        } else {
                            throw new ResponseException(errorCode, json.getString("error_message"));
                        }
                    }
                } catch (JSONException e) {
                    listener.onError(e);
                } catch (ResponseException e) {
                    listener.onResponseException(e);
                }

                mProgressDialog.cancel();
            }
        };
        request(url, params, listener, runnable);
    }
    
    /**
     * @deprecated
     * @param url
     * @param params
     * @param listener
     */
    public void request(final String url, final List<BasicNameValuePair> params, final RequestStringListener listener) {
        mProgressDialog.show();
        Runnable runnable = new Runnable(){
            public void run() {
                String response = requestData(url, params, listener);
                listener.onComplete(response);
                mProgressDialog.cancel();
            }
        };
        request(url, params, listener, runnable);
    }
    
    /**
     * @deprecated
     * @param url
     * @param params
     * @param listener
     * @param runnable
     */
    public void request(final String url, final List<BasicNameValuePair> params, final RequestBaseListener listener, Runnable runnable) {
        Log.d(TAG, "request " + url);
        Log.d(TAG, "params " + params.toString());
        Thread thread = new Thread(runnable);
        thread.start();
    }
    
    private String requestData(final String url, final List<BasicNameValuePair> params, RequestBaseListener listener) {
        String response = null;
        try {
            response = Util.request(url, params);
        } catch (IllegalStateException e) {
            listener.onError(e);
        } catch (UnsupportedEncodingException e) {
            //保证不会抛出的异常
        } catch (ClientProtocolException e) {
            listener.onError(e);
        } catch (IOException e) {
            listener.onIOException(e);
        } catch (HttpException e) {
            listener.onError(e);
        }
        return response;
    }
    
    public interface RequestBaseListener{
        public void onIOException(IOException e);
        public void onError(Exception e);
    }

    public interface RequestStringListener extends RequestBaseListener {
        public void onComplete(String response);

    }
    
    public interface RequestJsonListener extends RequestBaseListener {
        public void onComplete(JSONObject response);
        public void onResponseException(ResponseException e);
    }
    
    public void fetch(String url, FetchListener listener) {
        List<BasicNameValuePair> params = OAuth.createAuthParams();
        fetch(url, params, listener);
    }
    
    /**
     * request
     * @param url
     * @param params
     * @param listener
     */
    public void fetch(final String url, final List<BasicNameValuePair> params, final FetchListener listener) {
        if (isShowProgressDialog)
            mProgressDialog.show();
        mFetchListener = listener;
        
        new Thread(){
            public void run() {
                try {
                    String response = Utils.openUrl(url, params);
                    mHandler.sendMessage(mHandler.obtainMessage(FETCH_DATA_FINISH, response));
                } catch (NoHttpResponseException e) {
                    Log.w(TAG, e.getMessage());
                    mHandler.sendEmptyMessage(NET_ERROR);
                } catch (IOException e) {
                    Log.e(TAG, e.getMessage());
                    e.printStackTrace();
                } finally {
                    mProgressDialog.cancel();
                }
            }
        }.start();
    }
    
    private Handler mHandler = new Handler(){
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case NET_ERROR:
                displayToast(mContext.getString(R.string.net_error));
                break;
            case FETCH_DATA_FINISH:
                parseData((String) msg.obj);
                break;
            }
        }
    };
    
    /**
     * 解析
     * @param data
     */
    private void parseData(String data) {
        JSONObject json;
        try {
            json = new JSONObject(data);
            int errorCode;
            if ((errorCode = json.getInt("error_code")) == 0) {
                mFetchListener.onComplete(json);
            } else {
                int resId = ErrorMessage.getResId(errorCode);
                if (resId != 0) {
                    mFetchListener.onError(errorCode, mContext.getString(resId));
                }
                Log.w(TAG, errorCode + ":" + json.getString("error_message"));
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    
    private void displayToast(String text) {
        Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
    }
    
    public interface FetchListener {
        public void onComplete(JSONObject response);
        public void onError(int code, String msg);
    }
    
    public void setIsShowProgressDialog(boolean show) {
        isShowProgressDialog = show;
    }
}
